package com.star.io.netty.socket;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProtoPacket {
    private byte startCode = 0x68;     // 起始码
    private byte[] deviceId = new byte[6];  // 装置号码
    private byte command;       // 控制字
    private short dataLength;   // 数据域长度
    private String data;   // 数据域 变长
    private byte checkCode;    // 校验码
    private byte endCode = 0x16;  // 结束码

    public ProtoPacket(String deviceId, byte command, String data) {
        if (deviceId.length() > 6) {
            deviceId = deviceId.substring(0, 6);
        }
        this.deviceId = deviceId.getBytes(StandardCharsets.UTF_8);
        this.command = command;
        this.data = data;
        byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
        this.dataLength = (short) dataBytes.length;
        this.checkCode = getCheckCode(dataBytes);
    }

    // 计算校验和
    private byte getCheckCode(byte[] data) {
        int sum = 0;
        sum += startCode;
        for (byte b : deviceId) {
            sum += b;
        }
        sum += command;
        sum += dataLength >> 8;
        sum += (byte) dataLength;
        for (byte b : data) {
            sum += b;
        }
        return (byte) (sum & 0xff);
    }

    // 将 Message 编码为 ByteBuf(fer)
    public ByteBuf encode(ByteBufAllocator alloc) {
        byte[] contentBytes = data.getBytes(StandardCharsets.UTF_8);
        dataLength = (short) contentBytes.length;
        int totalLength = 1 + 6 + 1 + 2 + dataLength + 1 + 1;

        ByteBuf buf = alloc.buffer(totalLength);
        buf.writeByte(startCode);
        buf.writeBytes(deviceId);
        buf.writeByte(command);
        buf.writeShort(dataLength);
        buf.writeBytes(contentBytes);
        buf.writeByte(checkCode);
        buf.writeByte(endCode);

        return buf;
    }

    // 从 ByteBuf 解码为 Message  
    public static ProtoPacket decode(ByteBuf buf) {
        byte startCode = buf.readByte();
        byte[] deviceId = new byte[6];
        buf.readBytes(deviceId);
        byte command = buf.readByte();
        short dataLength = buf.readShort();
        byte[] contentBytes = new byte[dataLength];
        buf.readBytes(contentBytes);
        String content = new String(contentBytes, StandardCharsets.UTF_8);
        byte checkCode = buf.readByte();
        byte endCode = buf.readByte();
        ProtoPacket packet = new ProtoPacket(startCode, deviceId, command, dataLength, content, checkCode, endCode);
        if (checkCode != packet.getCheckCode()) {
            // 计算校验和未通过
            return null;
        }
        return packet;
    }

    @Override
    public String toString() {
        return "ProtoPacket{" +
                "startCode=" + Integer.toHexString(startCode) +
                ", deviceId=" + new String(deviceId, StandardCharsets.UTF_8) +
                ", command=" + Integer.toHexString(command) +
                ", dataLength=" + Integer.toHexString(dataLength) +
                ", data='" + data + '\'' +
                ", checkCode=" + Integer.toHexString(checkCode) +
                ", endCode=" + Integer.toHexString(endCode) +
                '}';
    }
}